// This is used by 3dsmax to load the correct parser
string ParamID = "0x003";

//Shadows have been *temporarily* dropped, in order to facilitate progress in other aspects of the mod!

//////////////////////////////////////////////////
//Matrices
//////////////////////////////////////////////////
float4x4 WorldIT : WorldInverseTranspose < string UIWidget = "None"; >;
float4x4 WorldViewProj : WorldViewProjection < string UIWidget = "None"; >;
float4x4 World : World < string UIWidget = "None"; >;
float4x4 ViewInv : ViewInverse < string UIWidget = "None"; >;

float4x4 gLightWVP : ViewINverse
<
	//string UIWidget = "None";
	string Object = "Spotlight";
	//string Space = "World";
>;

static const float SHADOW_EPSILON = 0.00005f;
//static const float SHADOW_EPSILON = 0.01f;
static const float SMAP_SIZE = 1024.0f;

float3   gLightPosL;

//////////////////////////////////////////////////
//Main Light
//////////////////////////////////////////////////
float3 LightDir : Direction
<
	string Object = "Spotlight";
	string Space = "World";
> = {0.0f, 0.5, -1.0f};//{1.0f, -1.0, 1.0f};

float4 LightColor1 : Diffuse <
    string UIName =  "Light1 Color";
    string Object = "Spotlight";
    string UIWidget = "Color";
> = {1.0f, 1.0f, 1.0f, 1.0f};

//////////////////////////////////////////////////
//Material surface
//////////////////////////////////////////////////
float4 MatDiffuse : Diffuse
<
    string UIName =  "Material Diffuse";
    string UIWidget = "Color";
> = {1.0f, 1.0f, 1.0f, 1.0f};

float4 MatAmbient : Ambient
<
    string UIName =  "Material Ambient";
    string UIWidget = "Color";
> = {0.0f, 0.0f, 0.0f, 1.0f};

float4 MatSpec : Specular
<
    string UIName =  "Material Specular";
    string UIWidget = "Color";
> = {1.0f, 1.0f, 1.0f, 1.0f};

float MatSpecPow : SpecularPower <
    string UIWidget = "slider";
    float UIMin = 1.0;
    float UIMax = 128.0;
    float UIStep = 1.0;
    string UIName =  "specular power";
> = 40.0;

float4 sceneambient
<
    string UIName =  "Scene Ambient";
    string UIWidget = "Color";
> = {0.0f, 0.0f, 0.0f, 1.0f};

float refmult : Environment
<
    string UIWidget = "slider";
    float UIMin = 0.0f;
    float UIMax = 2.0f;
    float UIStep = 0.001f;
    string UIName = "Reflection Multiplier";
> = 0.5f;

float textureSize = 256.0f;
//int textureSize = 256;
float normalStrength = 8;//was 8

//////////////////////////////////////////////////
//Textures
//////////////////////////////////////////////////

texture colorTexture : Diffuse <
    string ResourceName = "default_color.dds";
    string ResourceType = "2D";
>;

texture normalTexture : Normal <
    string ResourceName = "default_bump_normal.dds";
    string ResourceType = "2D";
>;

texture refcubeTexture : Environment <
    string ResourceName = "default_reflection.dds";
    string ResourceType = "CUBE";
>;

texture shadowTexture;
texture shadowcolortexture;

//////////////////////////////////////////////////
//Samplers
//////////////////////////////////////////////////

sampler2D colorSampler = sampler_state {
	Texture = <colorTexture>;
	MinFilter = Anisotropic;//these are settings from pix, running game on max settings
	MagFilter = Anisotropic;
	MipFilter = Linear;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	MIPMAPLODBIAS = 0.0f;
	MAXMIPLEVEL = 0;
	BORDERCOLOR = 0xFF000000;//argb
	MaxAnisotropy = 16;//0x10
};

sampler2D normalSampler = sampler_state {
	Texture = <normalTexture>;
	MinFilter = Anisotropic;//these are settings from pix, running game on max settings
	MagFilter = Anisotropic;
	MipFilter = Linear;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	MIPMAPLODBIAS = 0.0f;
	MAXMIPLEVEL = 0;
	BORDERCOLOR = 0xFF000000;//argb
	MaxAnisotropy = 16;//0x10
};

samplerCUBE envSampler = sampler_state {
	Texture = <refcubeTexture>;
	MinFilter = Anisotropic;//these are settings from pix, running game on max settings
	MagFilter = Anisotropic;
	MipFilter = Linear;
	AddressU = Wrap;
	AddressV = Wrap;
	AddressW = Wrap;
	MIPMAPLODBIAS = 0.0f;
	MAXMIPLEVEL = 0;
	BORDERCOLOR = 0xFF000000;//argb
	MaxAnisotropy = 16;//0x10
};

sampler ShadowMapS = sampler_state
{
	Texture = <shadowTexture>;
	MinFilter = Point;
	MagFilter = Point;
	MipFilter = None;
	AddressU  = Clamp; 
	AddressV  = Clamp;
};

sampler shadowcolorsamp = sampler_state
{
	Texture = <shadowcolortexture>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = None;
	AddressU  = Clamp; 
	AddressV  = Clamp;
};

//////////////////////////////////////////////////
//Structures
//////////////////////////////////////////////////

//Vertex structure from game
struct appdata {
	float4 Color 	: COLOR0;
    float3 Position	: POSITION;
    float2 UV		: TEXCOORD0;
};

//Vertex structure from game with normals
struct appdatan {
	float4 Color 	: COLOR0;
    float3 Position	: POSITION;
    float2 UV		: TEXCOORD0;
	float3 Normal	: NORMAL;
};

//data passed from the vertex shader to the pixel shader
struct vertexOutput {
    float4 HPosition	: POSITION;
    float4 vColor	: COLOR0;
    float2 TexCoord	: TEXCOORD0;
    float3 LightVec1	: TEXCOORD1;
    float3 WorldPos	: TEXCOORD2;
    float3 WorldEyePos	: TEXCOORD3;
};

//data passed from the vertex shader to the pixel shader
struct vertexOutputn {
    float4 HPosition	: POSITION;
    float4 vColor	: COLOR0;
    float2 TexCoord	: TEXCOORD0;
    float3 LightVec1	: TEXCOORD1;
    float3 WorldNormal	: TEXCOORD2;
    float3 WorldPos	: TEXCOORD3;
    float3 WorldEyePos	: TEXCOORD4;
};

//////////////////////////////////////////////////
//Shaders
//////////////////////////////////////////////////
float4x4 make_bias_mat(float BiasVal)
{
	float fTexWidth = SMAP_SIZE;
	float fTexHeight = SMAP_SIZE;
	// float fZScale = pow(2.0,((float)SHAD_BIT_DEPTH))-1.0; // dx8
	float fZScale = 1.0; //dx9
	float fOffsetX = 0.5f + (0.5f / fTexWidth);
	float fOffsetY = 0.5f + (0.5f / fTexHeight);
	float4x4 result = float4x4(0.5f,     0.0f,     0.0f,      0.0f,
					0.0f,    -0.5f,     0.0f,      0.0f,
					0.0f,     0.0f,     fZScale,   0.0f,
					fOffsetX, fOffsetY, -BiasVal,     1.0f );
	return result;
}

//Vertex Shader with normals
vertexOutputn mainVSBN(appdatan IN)
{	
	vertexOutputn OUT;
    OUT.WorldNormal = mul(IN.Normal, WorldIT).xyz;
    float4 Po = float4(IN.Position.xyz,1.0);
	float4 Pw = mul(Po, World);
    OUT.WorldPos = Pw;
    OUT.LightVec1 = normalize(-LightDir);
    OUT.TexCoord = IN.UV;
    OUT.WorldEyePos = ViewInv[3].xyz;
    OUT.HPosition = mul(Po, WorldViewProj);
    OUT.vColor = IN.Color;

    return OUT;
}
//vertex shader without normals
vertexOutput mainVSB(appdata IN)
{	
	vertexOutput OUT;
    float4 Po = float4(IN.Position.xyz,1.0);
	float4 Pw = mul(Po, World);
    OUT.WorldPos = Pw;
    OUT.LightVec1 = normalize(-LightDir);
    OUT.TexCoord = IN.UV;
    OUT.WorldEyePos = ViewInv[3].xyz;
    OUT.HPosition = mul(Po, WorldViewProj);
    OUT.vColor = IN.Color;

    return OUT;
}


float3 ComputeNormalsPS(in float2 uv:TEXCOORD0) : COLOR

    {
    float texelSize =  1.0f / textureSize ; //size of one texel
    
    float tl = abs(tex2D (colorSampler, uv + texelSize * float2(-1, -1)).x);   // top left
    float  l = abs(tex2D (colorSampler, uv + texelSize * float2(-1,  0)).x);   // left
    float bl = abs(tex2D (colorSampler, uv + texelSize * float2(-1,  1)).x);   // bottom left
    float  t = abs(tex2D (colorSampler, uv + texelSize * float2( 0, -1)).x);   // top
    float  b = abs(tex2D (colorSampler, uv + texelSize * float2( 0,  1)).x);   // bottom
    float tr = abs(tex2D (colorSampler, uv + texelSize * float2( 1, -1)).x);   // top right
    float  r = abs(tex2D (colorSampler, uv + texelSize * float2( 1,  0)).x);   // right
    float br = abs(tex2D (colorSampler, uv + texelSize * float2( 1,  1)).x);   // bottom right 

    // Compute dx using Sobel:
    //           -1 0 1 
    //           -2 0 2
    //           -1 0 1
    float dX = tr + 2*r + br -tl - 2*l - bl; 

    // Compute dy using Sobel:
    //           -1 -2 -1 
    //            0  0  0
    //            1  2  1
    float dY = bl + 2*b + br -tl - 2*t - tr; 

    // Build the normalized normal
    float3 N = float3(normalize(float3(dX, 1.0f / normalStrength, dY)));

    //convert (-1.0 , 1.0) to (0.0 , 1.0), if needed
    return N * 0.5f + 0.5f;
}

//Pixel Shader no effects - geometry has normals
float4 mainPSBN(vertexOutputn IN) : COLOR
{
    float4 map = tex2D(colorSampler,IN.TexCoord.xy);
    float3 Vn = normalize(IN.WorldEyePos - IN.WorldPos);
    float3 Nn = normalize(IN.WorldNormal);
    
    //normal map
    float3 bumps = tex2D(normalSampler,IN.TexCoord.xy).xyz - (0.5).xxx;
    Nn = Nn + (bumps.x + bumps.y);
    Nn = normalize(Nn);
    
    //spec
    float spec = bumps.z;
    
    //calc light vec
    float3 Ln = normalize(IN.LightVec1.xyz);
    float3 Hn = normalize(Vn + Ln);
    float hdn = pow(max(0,dot(Hn,Nn)),MatSpecPow);
    float ldn = dot(Ln,Nn);
    ldn = max(0.0,ldn);
    
    //blend sun light color
    float4 diffContrib = ldn * LightColor1;
    float4 specContrib = (ldn * hdn) * (LightColor1 * spec);
	
	//blend material diffuse, light color and ambient, add reflective light
	float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib)) * map + (specContrib);//fxcomposer doesn't have vertex colors
	//float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * diffContrib)) * map + (specContrib);//fxcomposer doesn't have vertex colors
	result.a = MatDiffuse.a * map.a;
	
	return result;
}

//Pixel Shader no effects - geometry does not have normals
float4 mainPSB(vertexOutput IN) : COLOR
{
    float4 map = tex2D(colorSampler,IN.TexCoord.xy);
    float3 Vn = normalize(IN.WorldEyePos - IN.WorldPos);;
    
    float mapspec = saturate(map);
    
    //generate normals + nmap
    //from net - http://forums.xna.com/forums/p/16619/87229.aspx, thanks to user "StatusUnknown"
    //float3 normal = normalize(cross(ddx(worldPosition.xyz),ddy(worldPosition.xyz)));
	float3 un = ddx(IN.WorldPos.xyz);
    float3 uv = ddy(IN.WorldPos.xyz);
    float3 Nn = normalize(cross(un,uv));
    
    float3 ngen = ComputeNormalsPS(IN.TexCoord.xy);
    //ngen.z = -ngen.z;
    Nn = normalize(Nn * ngen);
    //Nn = ngen;
    Nn = -Nn;//only necessary for gta
    
    //calc light vec
    float3 Ln = normalize(IN.LightVec1.xyz);
    float3 Hn = normalize(Vn + Ln);
    float hdn = pow(max(0,dot(Hn,Nn)),MatSpecPow);// * 1.0f;
    float ldn = dot(Ln,Nn);
    ldn = max(0.0,ldn);
    
    //blend sun light color
    float4 diffContrib = ldn * LightColor1;
    float4 specContrib = (ldn * hdn) * (LightColor1 * mapspec);//MatSpec, mapspec
	
	//blend material diffuse, light color and ambient, add reflective light
	float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib)) * map + (specContrib);//fxcomposer doesn't have vertex colors
	//float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * diffContrib)) * map + (specContrib);//fxcomposer doesn't have vertex colors
	result.a = MatDiffuse.a * map.a;
	
	return result;
}

//Pixel Shader reflection, geometry has normals
float4 mainPSRBN(vertexOutputn IN) : COLOR
{
    float4 map = tex2D(colorSampler,IN.TexCoord.xy);
    float3 Vn = normalize(IN.WorldEyePos - IN.WorldPos);
    float3 Nn = normalize(IN.WorldNormal);
    
    //normal map
    float3 bumps = tex2D(normalSampler,IN.TexCoord.xy).xyz - (0.5).xxx;
    Nn = Nn + (bumps.x + bumps.y);
    Nn = normalize(Nn);
    
    //spec
    float spec = bumps.z;
    
    //calc light vec
    float3 Ln = normalize(IN.LightVec1.xyz);
    float3 Hn = normalize(Vn + Ln);
    float hdn = pow(max(0,dot(Hn,Nn)),MatSpecPow);// * 1.0f;
    float ldn = dot(Ln,Nn);
    ldn = max(0.0,ldn);
    
    //reflection map coordinates are flipped and swizzled for GTA	
	float3 refvect = reflect(Vn,Nn);
	refvect.xyz = refvect.xzy;//this is expensive. it's either this, or multiple lights, but not both (under sm20)
	float4 reflColor = texCUBE(envSampler,-refvect.xyz );
    
    //blend sun light color
    float4 diffContrib = ldn * LightColor1;
    float4 specContrib = (ldn * hdn) * (LightColor1 * spec);
     
	//float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib * shadowCoeff)) * map + (specContrib * shadowCoeff);//fxcomposer doesn't have vertex colors
	float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib)) * map + (specContrib + (reflColor * refmult));//fxcomposer doesn't have vertex colors
	result.a = MatDiffuse.a * map.a;
	
	return result;
}

//Pixel Shader reflection, geometry does not have normals
float4 mainPSRB(vertexOutput IN) : COLOR
{
    float4 map = tex2D(colorSampler,IN.TexCoord.xy);
    float3 Vn = normalize(IN.WorldEyePos - IN.WorldPos);
    
    float4 mapspec = saturate(map);
    
    //generate normals + normal map
    float3 un = ddx(IN.WorldPos.xyz);
    float3 uv = ddy(IN.WorldPos.xyz);
    float3 Nn = normalize(cross(un,uv));
    
    //calc light vec
    float3 Ln = normalize(IN.LightVec1.xyz);
    float3 Hn = normalize(Vn + Ln);
    float hdn = pow(max(0,dot(Hn,Nn)),MatSpecPow);// * 1.0f;
    float ldn = dot(Ln,Nn);
    ldn = max(0.0,ldn);
    
    //reflection map coordinates are flipped and swizzled for GTA	
	float3 refvect = reflect(Vn,Nn);
	refvect.xyz = refvect.xzy;//this is expensive. it's either this, or multiple lights, but not both (under sm20)
	float4 reflColor = texCUBE(envSampler,-refvect.xyz );
    
    //blend sun light color
    float4 diffContrib = ldn * LightColor1;
    float4 specContrib = (ldn * hdn) * (LightColor1 * 1.0f);//MatSpec, mapspec
     
	//float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib * shadowCoeff)) * map + (specContrib * shadowCoeff);//fxcomposer doesn't have vertex colors
	float4 result = ((MatAmbient + sceneambient) + (MatDiffuse * IN.vColor * diffContrib)) * map + (specContrib + (reflColor * refmult));//fxcomposer doesn't have vertex colors
	result.a = MatDiffuse.a * map.a;
	
	return result;
}

/*
void BuildShadowMapVS(float3 posL : POSITION0,
                      out float4 posH : POSITION0,
                      out float  depth : TEXCOORD0)
{
	// Render from light's perspective.
	posH = mul(float4(posL, 1.0f), gLightWVP);
	
	// Depth from vertex to light source.
	depth = distance(posL, gLightPosL);
}

float4 BuildShadowMapPS(float2 depth : TEXCOORD0) : COLOR
{
	// Each pixel in the shadow map stores the pixel depth from the 
	// light source in normalized device coordinates.
	return depth.x / depth.y; // z / w
}
*/

void BuildShadowMapVS(float3 posL : POSITION0,
                      out float4 posH : POSITION0,
                      out float  depth : TEXCOORD0)
{
	// Render from light's perspective.
	posH = mul(float4(posL, 1.0f), gLightWVP);
	
	// Depth from vertex to light source.
	//depth = distance(posL, gLightPosL);
	depth = posH.zw;
}

float4 BuildShadowMapPS(float2 depth : TEXCOORD0) : COLOR
{
	// Each pixel in the shadow map stores the pixel depth from the 
	// light source in normalized device coordinates.
	return depth.x / depth.y; // z / w
	//float4 matcolor = {0,0,0,1};
	//return matcolor;
}


//////////////////////////////////////////////////
//Technique - used by game!
//do not change alphs settings here, as they are overwritten in the dll to be compatible
//with the Rw device cache
//////////////////////////////////////////////////

//main buildings, no material effects. geometry has normals
technique StaticBuild
{
	pass p0
	{
		VertexShader = compile vs_2_0 mainVSBN();
		PixelShader = compile ps_2_a mainPSBN();
	}
}

//main buildings, no material effects. geometry does not have normals
//and will generate normals in the pixel shader
technique StaticBuild_ngen
{
	pass p0
	{
		VertexShader = compile vs_2_0 mainVSB();
		PixelShader = compile ps_2_a mainPSB();
	}
}

technique RefBuild
{
	pass p0
	{
		VertexShader = compile vs_2_0 mainVSBN();
		PixelShader = compile ps_2_a mainPSRBN();
	}
	/*
	//multipass works, but no use for it yet
	pass p1
	{
		VertexShader = compile vs_2_0 mainVSB();
		PixelShader = compile ps_2_a mainPSRB();
		Fillmode = point;
	}
	*/
}

technique RefBuild_ngen
{
	pass p0
	{
		VertexShader = compile vs_2_0 mainVSB();
		PixelShader = compile ps_2_a mainPSRB();
	}
	/*
	//multipass works, but no use for it yet
	pass p1
	{
		VertexShader = compile vs_2_0 mainVSB();
		PixelShader = compile ps_2_a mainPSRB();
		Fillmode = point;
	}
	*/
}

technique RefBuildShadowed
{
	pass p0
	{
		VertexShader = compile vs_2_0 mainVSB();
		PixelShader = compile ps_2_a mainPSRB();
		//AlphaRef = 0x40;
		//AlphaFunc = GreaterEqual;
		//AlphaTestEnable = TRUE;
		//Cullmode = None;
		//ZEnable = true;
		//ZWriteEnable = true;
		//ZFunc = GreaterEqual;
	}
}

technique BuildCreateShadow
{
	pass p0
	{
		vertexShader = compile vs_2_0 BuildShadowMapVS();
        	pixelShader  = compile ps_2_0 BuildShadowMapPS();
		//AlphaBlendEnable = FALSE;
		//AlphaTestEnable = TRUE;
		//AlphaFunc = Less;
		//AlphaRef = 0x80;
		//cullmode = None;
		//ZEnable = true;
		//ZWriteEnable = true;
		//ZFunc = GreaterEqual;
	}
}